package org.tagging.controller;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import org.tagging.component.security.LoginSuccessHandler;
import org.tagging.exception.LoginWrongPlaceException;
import org.tagging.model.TaggingAuthority;
import org.tagging.model.TaggingUser;
import org.tagging.model.TaggingUserAuthority;
import org.tagging.service.impl.other.AuthorityServiceImpl;
import org.tagging.service.impl.other.AuthorityUserServiceImpl;
import org.tagging.service.impl.other.ClientUserServiceImpl;
import org.tagging.utils.Asserts;
import org.tagging.utils.ResponseUtils;
import org.tagging.utils.RoleEnum;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

@RestController
@RequestMapping("/api/tagging/admin")
@Api(value = "管理员相关操作", tags = "管理员相关操作")
public class AdminUserController implements InitializingBean {
    private Logger logger = LoggerFactory.getLogger(AdminUserController.class);


//    private Set<TaggingUserAuthority> set;//权限模版

    private Map<String, Integer> authorityTemplate;
    private Map<Integer, String> reversedAuthorityTemplate;
    private Map<String, Boolean> authorityBoolean;
    private Map<String, Boolean> userAuthorities;
    private Map<String, Boolean> adminAuthorities;
//    private List<UserAuthorityTemplate.TaggingUserAuthorityTemplate> l;


    @Qualifier("clientUserServiceImpl")
    @Autowired
    private ClientUserServiceImpl userService;

    @Autowired
    private LoginSuccessHandler loginSuccessHandler;
    @Autowired
    private AuthorityServiceImpl authorityService;
    @Autowired
    private AuthorityUserServiceImpl authorityUserService;

    public AdminUserController() {
    }

    @Override
    public void afterPropertiesSet() {
        //容器初始化后即从数据库中获取权限模板
        List<TaggingUserAuthority> taggingUserAuthorities = authorityUserService.queryTemplate();
        //加载普通角色那边对应的所有权限
        List<String> roleAuthorities = authorityService.queryAllAuthorities();
        authorityBoolean = new HashMap<>(taggingUserAuthorities.size());
        adminAuthorities = new HashMap<>();
        userAuthorities = new HashMap<>();
        reversedAuthorityTemplate = new HashMap<>();
        authorityTemplate = new HashMap<>();
        //构造权限模版
        for (TaggingUserAuthority taggingUserAuthority : taggingUserAuthorities) {
            authorityTemplate.put(taggingUserAuthority.getAuthority(), taggingUserAuthority.getId());
            authorityBoolean.put(taggingUserAuthority.getAuthority(), false);
            reversedAuthorityTemplate.put(taggingUserAuthority.getId(), taggingUserAuthority.getAuthority());
        }
        for (String roleAuthority : roleAuthorities) {
            authorityBoolean.put(roleAuthority, false);
        }
        List<TaggingAuthority> adminAs = authorityService.queryByRoleId(RoleEnum.ADMIN.value());
        for (TaggingAuthority adminA : adminAs) {
            adminAuthorities.put(adminA.getAuthority(), true);
        }
        List<TaggingAuthority> userAs = authorityService.queryByRoleId(RoleEnum.USER.value());
        for (TaggingAuthority userA : userAs) {
            userAuthorities.put(userA.getAuthority(), true);
        }
        logger.info("加载权限模版成功！");
    }

    private Map<String, Boolean> retrieveAuthoritiesByRole(RoleEnum roleEnum) {
        switch (roleEnum) {
            case USER:
                return userAuthorities;
            case ADMIN:
                return adminAuthorities;
        }
        throw new UnsupportedOperationException("Role is not support!->" + roleEnum.name());
    }

    @PostMapping("/login")
    @ApiOperation(value = "管理员的登陆")
    public void login(@RequestParam("username") String username, @RequestParam("password") String password,
                      HttpServletRequest request, HttpServletResponse response) throws ServletException, LoginWrongPlaceException, IOException {
//        String username = request.getParameter("username");
//        String password = request.getParameter("password");
        //此方法会调用登陆逻辑，若用户名或密码错误也会抛出错误
        SecurityContextHolder.clearContext();
        request.login(username, password);
        TaggingUser user = userService.queryByUsername(username, TaggingUser.Column.id, TaggingUser.Column.role);
        Asserts.isAdmin(user.getRole(), "用户名登录错地方!");
        loginSuccessHandler.onAuthenticationSuccess(request, response, SecurityContextHolder.getContext().getAuthentication());
    }

    @ApiOperation(notes = "所需权限（12.retrieve_all_users）", value = "获取用户的标注数据量")
    @PreAuthorize("hasAnyRole('ADMIN') or hasAuthority('retrieve_all_users')")
    @GetMapping(value = "/userStatistic", produces = "application/json;charset=utf-8")
    public List<TaggingUser> retrieveUsersStatistic(@RequestParam("page") Integer page, @RequestParam("pageSize") Integer pageSize) {
        return userService.querySelectiveWithPagination(page, pageSize, TaggingUser.Column.id, TaggingUser.Column.role, TaggingUser.Column.username, TaggingUser.Column.lastLoginTime, TaggingUser.Column.indonesiaCompleteToday, TaggingUser.Column.malayCompleteToday, TaggingUser.Column.indonesiaTotal, TaggingUser.Column.malayTotal, TaggingUser.Column.philippinesTotal, TaggingUser.Column.philippinesCompleteToday);
    }

    @ApiOperation(notes = "所需权限(12.retrieve_all_users)", value = "获取用户及其权限")
    @PreAuthorize("hasAnyRole('ADMIN') or hasAuthority('retrieve_all_users')")
    @GetMapping(value = "/users", produces = "application/json;charset=utf-8")
    public String retrieveUsers(@RequestParam("page") Integer page, @RequestParam("pageSize") Integer pageSize) {
        List<TaggingUser> taggingUsers = userService.querySelectiveWithPagination(page, pageSize, TaggingUser.Column.id, TaggingUser.Column.role, TaggingUser.Column.username, TaggingUser.Column.lastLoginTime, TaggingUser.Column.indonesiaCompleteToday, TaggingUser.Column.malayCompleteToday, TaggingUser.Column.indonesiaTotal, TaggingUser.Column.malayTotal);
        List<UserInfo> userAuthorities = new LinkedList<>();
        for (TaggingUser taggingUser : taggingUsers) {
            HashMap<String, Boolean> tmpAuthorityMap = new HashMap<>(authorityBoolean);
            UserInfo userAuthority = new UserInfo();
            userAuthority.userId = taggingUser.getId();
            userAuthority.username = taggingUser.getUsername();
            userAuthority.role = taggingUser.getRole();
//            userAuthority.malayCompleteToday = taggingUser.getMalayCompleteToday();
//            userAuthority.malayTotal = taggingUser.getMalayTotal();
//            userAuthority.indonesianCompleteToday = taggingUser.getIndonesiaCompleteToday();
//            userAuthority.indonesianTotal = taggingUser.getIndonesiaTotal();
//            userAuthority.philippinesCompleteToday = taggingUser.getPhilippinesCompleteToday();
//            userAuthority.philippinesTotal = taggingUser.getPhilippinesTotal();
            userAuthority.authorities = new ArrayList<>(tmpAuthorityMap.size());
            List<TaggingUserAuthority> taggingUserAuthorities = authorityUserService.queryByUserId(taggingUser.getId());
            authorityService.queryByRoleId(taggingUser.getRole());
            Map<String, Boolean> roleAuthorities = retrieveAuthoritiesByRole(RoleEnum.fromIntegerToRoleEnum(taggingUser.getRole()));
            tmpAuthorityMap.putAll(roleAuthorities);
            for (TaggingUserAuthority taggingUserAuthority : taggingUserAuthorities) {
                if (tmpAuthorityMap.get(taggingUserAuthority.getAuthority()) != null) {
                    tmpAuthorityMap.put(taggingUserAuthority.getAuthority(), true);
                }
            }
//            userAuthority.authorities = tmpAuthorityMap;
            userAuthority.authorities = new ArrayList<>(tmpAuthorityMap.size());
            tmpAuthorityMap.forEach((k, v) -> {
                userAuthority.authorities.add(new UserInfo.Authority(authorityTemplate.get(k), k, v));
            });
            //此时该tmpAuthority即代表当前用户的所有的权限
            userAuthorities.add(userAuthority);
        }
        Map<String, Object> map = new HashMap<>();
        map.put("users", userAuthorities);
        map.put("total", userService.queryCount());
        return ResponseUtils.build(HttpStatus.OK.value(), "获取所有用户成功！", map);
    }


    private static class UserInfo {
        Integer userId;
        String username;
        Integer role;
        //        Integer indonesianCompleteToday;
//        Integer indonesianTotal;
//        Integer malayCompleteToday;
//        Integer malayTotal;
//        Integer philippinesCompleteToday;
//        Integer philippinesTotal;
        List<Authority> authorities;

        public List<Authority> getAuthorities() {
            return authorities;
        }

        public void setAuthorities(List<Authority> authorities) {
            this.authorities = authorities;
        }

        private static class Authority {
            Integer authorityId;
            Boolean privilege;
            String name;


            public Authority(Integer authorityId, String name, Boolean privilege) {
                this.authorityId = authorityId;
                this.privilege = privilege;
                this.name = name;
            }

            public String getName() {
                return name;
            }

            public void setName(String name) {
                this.name = name;
            }

            public Boolean getPrivilege() {
                return privilege;
            }

            public void setPrivilege(Boolean privilege) {
                this.privilege = privilege;
            }

            public Integer getAuthorityId() {
                return authorityId;
            }

            public void setAuthorityId(Integer authorityId) {
                this.authorityId = authorityId;
            }
        }
//        Map<String, Boolean> authorities;

        public void setUserId(Integer userId) {
            this.userId = userId;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public Integer getRole() {
            return role;
        }

        public void setRole(Integer role) {
            this.role = role;
        }


        public int getUserId() {
            return userId;
        }

        public String getUsername() {
            return username;
        }

    }

    //改变权限的状态
    @PostMapping(value = "/authority", produces = "application/json;charset=utf-8")
    @PreAuthorize("hasAnyRole('ADMIN') or hasAuthority('user_authority_modification')")
    @ApiOperation(value = "修改某一用户的权限", notes = "所需权限(14.user_authority_modification)")
    public String changeAuthorityState(@RequestParam("userId") Integer userId,
                                       @RequestParam("authorityId") Integer authorityId,
                                       @ApiParam(value = "state=> on(为该用户打开该权限) off(为该用户移除该权限)") @RequestParam("state") String state) {
        String authorityName = reversedAuthorityTemplate.get(authorityId);
        Assert.notNull(authorityName, "当前权限不存在！->authorityId:" + authorityId);
        switch (state) {
            case "on": {
                authorityUserService.addAuthorityUser(authorityName, userId);
                logger.info("添加用户(userId:{})权限成功！", userId);
                break;
            }
            case "off": {
                authorityUserService.removeAuthorityUser(authorityName, userId);
                logger.info("移除用户(userId:{})权限成功！", userId);
                break;
            }
            default:
                throw new UnsupportedOperationException("state值不支持,请输入 state值应为 on/off;");
        }
        return ResponseUtils.build(HttpStatus.OK.value(), "修改用户权限成功!");
    }
}
